package tecnicas;

import java.util.ArrayList;

import matriz.Matriz;
import datosFamilias.*;


public class ArrowRaynaudMejorado extends TecnicaAbstracta
{
    private Matriz matrizDeClasificacion;
    private ArrayList<Familia> familias;
    private float MAX = 9999999999f;
    
    public ArrowRaynaudMejorado(ArrayList<String> valoresMatriz, ArrayList<Familia> fam, int numTecnica, int cantCriterios)
    {
        familias = fam;
        numeroDeTecnica = numTecnica;
        cantidadDeCriterios = cantCriterios;
        
        cargarPriorizacionCriterios(valoresMatriz, cantidadDeCriterios);
        
        generarMatrizDeClasificacion();
    }

    private void generarMatrizDeClasificacion()
    {
        matrizDeClasificacion = new Matriz(familias.size(), familias.size());
        for(int familiaFila = 0; familiaFila < familias.size(); familiaFila++)
        {
            matrizDeClasificacion.agregarValor(familiaFila, familiaFila, 0f);
            ArrayList<Integer> valoresFamFila = new ArrayList<Integer>();
            Familia famActual = familias.get(familiaFila);
            for(int index = 0; index < cantidadDeCriterios; index++)
            {
                valoresFamFila.add(famActual.calcularPuntajes(index));
            }
            for(int famIndex = familiaFila+1; famIndex < familias.size(); famIndex++)
            {
                float valor = 0f;
                Familia famCol = familias.get(famIndex);
                for(int index = 0; index < cantidadDeCriterios; index++)
                {
                    if(famCol.calcularPuntajes(index) < valoresFamFila.get(index))
                    {
                        valor += priorizacionCriterios.get(index);
                    }
                    else
                    {
                        if(famCol.calcularPuntajes(index) == valoresFamFila.get(index))
                        {
                            valor += priorizacionCriterios.get(index)*0.5f;
                        }
                    }
                }
                matrizDeClasificacion.agregarValor(familiaFila, famIndex, valor);
                matrizDeClasificacion.agregarValor(famIndex, familiaFila, 1 - valor);
            }
        }
    }
    
    @Override
    public ArrayList<Familia> calcularResultados() 
    { 
        ArrayList<Familia> resultado = new ArrayList<Familia>();
        boolean[] familiasSeleccionadas = inicializarArreglo();
        while(resultado.size() < familias.size())
        {
            // obtenemos los maximos
            ArrayList<Float> maximosFam = new ArrayList<Float>();
            for(int index = 0; index < familias.size(); index++)
            {
                if(familiasSeleccionadas[index])
                {
                    maximosFam.add(null);
                }
                else
                {
                    maximosFam.add(obtenerMaximoFila(index, familiasSeleccionadas));
                }
            }
            
            // obtenemos los minimos
            ArrayList<Integer> minimos = obtenerMinimo(maximosFam);
            for(int index = minimos.size()-1; index >= 0; index--)
            {
                resultado.add(0, familias.get(minimos.get(index)));
                familiasSeleccionadas[minimos.get(index)] = true;
            }
        }
        return resultado;
    }
    
    private float obtenerMaximoFila(int fila, boolean[] famSel)
    {
        float maximo = -1;
        for(int col = 0; col < familias.size(); col++)
        {
            if(!famSel[col])
            {
                float actual = matrizDeClasificacion.obtenerValor(fila, col);
                if(maximo < actual)
                {
                    maximo = actual;
                }
            }
        }
        return maximo;
    }
    
    private ArrayList<Integer> obtenerMinimo(ArrayList<Float> fam)
    {
        ArrayList<Integer> minimos = new ArrayList<Integer>();
        float valorMinimo = MAX;
        for(int index = 0; index < fam.size(); index++)
        {
            if(fam.get(index) != null)
            {
                float minimoAct = fam.get(index);
                if(valorMinimo > minimoAct)
                {
                    minimos = new ArrayList<Integer>();
                    valorMinimo = minimoAct;
                    minimos.add(index);
                }
                else
                {
                    if(valorMinimo == minimoAct)
                    {
                        minimos.add(index);
                    }
                }
            }
        }
        return minimos;
    }
    
    private boolean[] inicializarArreglo()
    {
        boolean[] arr = new boolean[familias.size()];
        for(int index = 0; index < familias.size(); index++)
        {
            arr[index] = false;
        }
        return arr;
    }
}
